#!BPY
""" 
Name: 'Unreal Skeletal Mesh/Animation PSK/PSA MOD' 
Blender: 245
Group: 'Export' 
Tooltip: 'Unreal Skeletal Mesh and Animation Export (*.psk, *.psa)' 
""" 
__author__ = "Optimus_P-Fat/Active_Trash" 
__version__ = "0.0.4 BETA" 
__bpydoc__ = """\ 

-- Unreal Skeletal Mesh and Animation Export (.psk  and .psa) export script v0.0.1 --<br> 

- NOTES:
- This script Exports To Unreal's PSK and PSA file formats for Skeletal Meshes and Animations. <br>
- This script DOES NOT support vertex animation! These require completely different file formats. <br>

- v0.0.1
- Initial version

- v0.0.2
- This version adds support for more than one material index!

- v0.0.3
- Working on this version for main bone fixed and the update for Blender 2.45. Update By: Darknet
- Note different UTXXXX game little different but with the same format build.
- Work on parent and child id number and number of bone are counted. There was a miss count for the bone that was sure it that part kept giving error
- PSA is not work it the old version of the blender most of the blender is not use any more.

- v0.0.4
- Added the support for GUI menu frame.
- psa still doesn't work.

TO DO LIST:
-Need to fixed bone id iusses 
-Clean up the codes later
-got to learn blender animation acyion

""" 
# DANGER! This code is complete garbage!  Do not read!
# TODO: Throw some liscence junk in here: (maybe some GPL?)
# Liscence Junk: Use this script for whatever you feel like! 

import Blender, time, os, math, sys as osSys, operator
from Blender import sys, Window, Draw, Scene, Mesh, Material, Texture, Image, Mathutils, Armature

from cStringIO import StringIO
from struct import pack, calcsize

# REFERENCE MATERIAL JUST IN CASE:
# 
# U = x / sqrt(x^2 + y^2 + z^2)
# V = y / sqrt(x^2 + y^2 + z^2)
#
# Triangles specifed counter clockwise for front face
#

# Events
EVENT_NOEVENT = 1
EVENT_DRAW = 2
EVENT_EXIT = 3
EVENT_EXPORT = 4
EVENT_TRIANGLES = 5
EVENT_FILEPATH = 6
EVENT_CHECKMESH = 7
EVENT_PSK_EXT = 8
EVENT_PSA_EXT = 9
EVENT_STARTFRAME = 1
EVENT_ENDFRAME = 2
EVENT_FRAMENAME = 10
startframe = Draw.Create(1)
endframe = Draw.Create(4)
maxframe = 250
string = Draw.Create("demo_frame")
#Menu
Menu_Height = 20
#defines for sizeofs
SIZE_FQUAT = 16
SIZE_FVECTOR = 12
SIZE_VJOINTPOS = 44
SIZE_ANIMINFOBINARY = 168
SIZE_VCHUNKHEADER = 32
SIZE_VMATERIAL = 88
SIZE_VBONE = 120
SIZE_FNAMEDBONEBINARY = 120
SIZE_VRAWBONEINFLUENCE = 12
SIZE_VQUATANIMKEY = 32
SIZE_VVERTEX = 16
SIZE_VPOINT = 12
SIZE_VTRIANGLE = 12

########################################################################
# Generic Object->Integer mapping
# the object must be usable as a dictionary key

class ObjMap:
	def __init__(self):
		self.dict = {}
		self.next = 0
	def get(self, obj):
		if (obj in self.dict):
			return self.dict[obj]
		else:
			id = self.next
			self.next = self.next + 1
			self.dict[obj] = id
			return id
			
	def items(self):
		getval = operator.itemgetter(0)
		getkey = operator.itemgetter(1)
		return map(getval, sorted(self.dict.items(), key=getkey))



########################################################################
# RG - UNREAL DATA STRUCTS - CONVERTED FROM C STRUCTS GIVEN ON UDN SITE 
#Animation file data structures 
#Copyright 1997-2003 Epic Games, Inc. All Rights Reserved.
# provided here: http://udn.epicgames.com/Two/BinaryFormatSpecifications.html
class FQuat:
	def __init__(self): 
		self.X = 0.0
		self.Y = 0.0
		self.Z = 0.0
		self.W = 1.0
		
	def dump(self):
		data = pack('ffff', self.X, self.Y, self.Z, self.W)
		return data
		
	def __cmp__(self, other):
		return cmp(self.X, other.X) \
			or cmp(self.Y, other.Y) \
			or cmp(self.Z, other.Z) \
			or cmp(self.W, other.W)
		
	def __hash__(self):
		return hash(self.X) ^ hash(self.Y) ^ hash(self.Z) ^ hash(self.W)
		
	def __str__(self):
		return "[%f,%f,%f,%f](FQuat)" % (self.X, self.Y, self.Z, self.W)
		
class FVector:
	def __init__(self, X=0.0, Y=0.0, Z=0.0):
		self.X = X
		self.Y = Y
		self.Z = Z
		
	def dump(self):
		data = pack('fff', self.X, self.Y, self.Z)
		return data
		
	def __cmp__(self, other):
		return cmp(self.X, other.X) \
			or cmp(self.Y, other.Y) \
			or cmp(self.Z, other.Z)
		
	def __hash__(self):
		return hash(self.X) ^ hash(self.Y) ^ hash(self.Z)
		
	def dot(self, other):
		return self.X * other.X + self.Y * other.Y + self.Z * other.Z
	
	def cross(self, other):
		return FVector(self.Y * other.Z - self.Z * other.Y,
				self.Z * other.X - self.X * other.Z,
				self.X * other.Y - self.Y * other.X)
				
	def sub(self, other):
		return FVector(self.X - other.X,
			self.Y - other.Y,
			self.Z - other.Z)

class VJointPos:
	def __init__(self):
		self.Orientation = FQuat()
		self.Position = FVector()
		self.Length = 0.0
		self.XSize = 0.0
		self.YSize = 0.0
		self.ZSize = 0.0
		
		
	def dump(self):
		data = self.Orientation.dump() + self.Position.dump() + pack('4f', self.Length, self.XSize, self.YSize, self.ZSize)
		return data
		
		
class AnimInfoBinary:
	def __init__(self):
		self.Name = "" # length=64
		#print self.Name
		self.Group = ""	# length=64
		self.TotalBones = 0
		self.RootInclude = 0
		self.KeyCompressionStyle = 0
		self.KeyQuotum = 0
		self.KeyPrediction = 0.0
		self.TrackTime = 0.0
		self.AnimRate = 0.0
		self.StartBone = 0
		self.FirstRawFrame = 0
		self.NumRawFrames = 0
		
	def dump(self):
		data = pack('64s64siiiifffiii', self.Name, self.Group, self.TotalBones, self.RootInclude, self.KeyCompressionStyle, self.KeyQuotum, self.KeyPrediction, self.TrackTime, self.AnimRate, self.StartBone, self.FirstRawFrame, self.NumRawFrames)
		return data
		
		
class VChunkHeader:
	def __init__(self, name, type_size):
		self.ChunkID = name # length=20
		self.TypeFlag = 1999801 # special value
		self.DataSize = type_size
		self.DataCount = 0
		
	def dump(self):
		data = pack('20siii', self.ChunkID, self.TypeFlag, self.DataSize, self.DataCount)
		return data
		

class VMaterial:
	def __init__(self):
		self.MaterialName = "" # length=64
		self.TextureIndex = 0
		self.PolyFlags = 0 # DWORD
		self.AuxMaterial = 0
		self.AuxFlags = 0 # DWORD
		self.LodBias = 0
		self.LodStyle = 0
		
	def dump(self):
		data = pack('64siLiLii', self.MaterialName, self.TextureIndex, self.PolyFlags, self.AuxMaterial, self.AuxFlags, self.LodBias, self.LodStyle)
		return data

		
class VBone:
	def __init__(self):
		self.Name = "" # length = 64
		print self.Name
		self.Flags = 0 # DWORD
		self.NumChildren = 0
		#self.ParentIndex = 0
		self.ParentIndex = 0
		#print "PARENT INDEX", self.ParentIndex
		self.BonePos = VJointPos()
		
	def dump(self):
		data = pack('64sLii', self.Name, self.Flags, self.NumChildren, self.ParentIndex) + self.BonePos.dump()
		return data

		
#same as above - whatever - this is how Epic does it...
#Unreal Vertex Animation data structure details
#Copyright 1997-2003 Epic Games, Inc. All Rights Reserved.
class FNamedBoneBinary:
	def __init__(self):
		self.Name = "" # length = 64
		#print self.Name
		self.Flags = 0 # DWORD
		self.NumChildren = 0
		self.ParentIndex = 0
		self.BonePos = VJointPos()
		
		self.IsRealBone = 0  # this is set to 1 when the bone is actually a bone in the mesh and not a dummy
		
	def dump(self):
		data = pack('64sLii', self.Name, self.Flags, self.NumChildren, self.ParentIndex) + self.BonePos.dump()
		#print self.ParentIndex
		return data
	
	
class VRawBoneInfluence:
	def __init__(self):
		self.Weight = 0.0
		self.PointIndex = 0
		self.BoneIndex = 0
		
	def dump(self):
		data = pack('fii', self.Weight, self.PointIndex, self.BoneIndex)
		return data
		
		
class VQuatAnimKey:
	def __init__(self):
		self.Position = FVector()
		self.Orientation = FQuat()
		self.Time = 0.0
		
	def dump(self):
		data = self.Position.dump() + self.Orientation.dump() + pack('f', self.Time)
		return data
		
		
class VVertex:
	def __init__(self):
		self.PointIndex = 0 # WORD
		self.U = 0.0
		self.V = 0.0
		self.MatIndex = 0 #BYTE
		self.Reserved = 0 #BYTE
		
	def dump(self):
		data = pack('HHffBBH', self.PointIndex, 0, self.U, self.V, self.MatIndex, self.Reserved, 0)
		return data
		
	def __cmp__(self, other):
		return cmp(self.PointIndex, other.PointIndex) \
			or cmp(self.U, other.U) \
			or cmp(self.V, other.V) \
			or cmp(self.MatIndex, other.MatIndex) \
			or cmp(self.Reserved, other.Reserved)
			
	def __hash__(self):
		return hash(self.PointIndex) \
			^ hash(self.U) ^ hash(self.V) \
			^ hash(self.MatIndex) \
			^ hash(self.Reserved)
		
class VPoint:
	def __init__(self):
		self.Point = FVector()
		
	def dump(self):
		return self.Point.dump()
		
	def __cmp__(self, other):
		return cmp(self.Point, other.Point)
		
	def __hash__(self):
		return hash(self.Point)
		
class VTriangle:
	def __init__(self):
		self.WedgeIndex0 = 0 # WORD
		self.WedgeIndex1 = 0 # WORD
		self.WedgeIndex2 = 0 # WORD
		self.MatIndex = 0 # BYTE
		self.AuxMatIndex = 0 # BYTE
		self.SmoothingGroups = 0 # DWORD
		
		
	def dump(self):
		data = pack('HHHBBL', self.WedgeIndex0, self.WedgeIndex1, self.WedgeIndex2, self.MatIndex, self.AuxMatIndex, self.SmoothingGroups)
		return data


# END UNREAL DATA STRUCTS
########################################################################

#RG - helper class to handle the normal way the UT files are stored 
#as sections consisting of a header and then a list of data structures
class FileSection:
	def __init__(self, name, type_size):
		self.Header = VChunkHeader(name, type_size)
		self.Data = [] # list of datatypes
		
	def dump(self):
		data = self.Header.dump()
		for i in range(len(self.Data)):
			data = data + self.Data[i].dump()
		return data
		
	def UpdateHeader(self):
		self.Header.DataCount = len(self.Data)
		
		
class PSKFile:
	def __init__(self):
		self.GeneralHeader = VChunkHeader("ACTRHEAD", 0)
		self.Points = FileSection("PNTS0000", SIZE_VPOINT)		#VPoint
		self.Wedges = FileSection("VTXW0000", SIZE_VVERTEX)		#VVertex
		self.Faces = FileSection("FACE0000", SIZE_VTRIANGLE)		#VTriangle
		self.Materials = FileSection("MATT0000", SIZE_VMATERIAL)	#VMaterial
		self.Bones = FileSection("REFSKELT", SIZE_VBONE)		#VBone
		self.Influences = FileSection("RAWWEIGHTS", SIZE_VRAWBONEINFLUENCE)	#VRawBoneInfluence
		
		
		#RG - this mapping is not dumped, but is used internally to store the new point indices 
		# for vertex groups calculated during the mesh dump, so they can be used again
		# to dump bone influences during the armature dump
		#
		# the key in this dictionary is the VertexGroup/Bone Name, and the value
		# is a list of tuples containing the new point index and the weight, in that order
		#
		# Layout:
		# { groupname : [ (index, weight), ... ], ... }
		#
		# example: 
		# { 'MyVertexGroup' : [ (0, 1.0), (5, 1.0), (3, 0.5) ] , 'OtherGroup' : [(2, 1.0)] }
		
		self.VertexGroups = {} 
		
		
	def AddPoint(self, p):
		#print 'AddPoint'
		self.Points.Data.append(p)
		
	def AddWedge(self, w):
		#print 'AddWedge'
		self.Wedges.Data.append(w)
	
	def AddFace(self, f):
		#print 'AddFace'
		self.Faces.Data.append(f)
		
	def AddMaterial(self, m):
		#print 'AddMaterial'
		self.Materials.Data.append(m)
		
	def AddBone(self, b):
		#print 'AddBone [%s]: Position: (x=%f, y=%f, z=%f) Rotation=(%f,%f,%f,%f)'  % (b.Name, b.BonePos.Position.X, b.BonePos.Position.Y, b.BonePos.Position.Z, b.BonePos.Orientation.X,b.BonePos.Orientation.Y,b.BonePos.Orientation.Z,b.BonePos.Orientation.W)
		self.Bones.Data.append(b)
		
	def AddInfluence(self, i):
		#print 'AddInfluence'
		self.Influences.Data.append(i)
		
	def UpdateHeaders(self):
		self.Points.UpdateHeader()
		self.Wedges.UpdateHeader()
		self.Faces.UpdateHeader()
		self.Materials.UpdateHeader()
		self.Bones.UpdateHeader()
		self.Influences.UpdateHeader()
		
	def dump(self):
		self.UpdateHeaders()
		data = self.GeneralHeader.dump() + self.Points.dump() + self.Wedges.dump() + self.Faces.dump() + self.Materials.dump() + self.Bones.dump() + self.Influences.dump()
		return data
		
	def GetMatByIndex(self, mat_index):
		if mat_index >= 0 and len(self.Materials.Data) > mat_index:
			return self.Materials.Data[mat_index]
		else:
			m = VMaterial()
			m.MaterialName = "Mat%i" % mat_index
			self.AddMaterial(m)
			return m
		
	def PrintOut(self):
		print '--- PSK FILE EXPORTED ---'
		print 'point count: %i' % len(self.Points.Data)
		print 'wedge count: %i' % len(self.Wedges.Data)
		print 'face count: %i' % len(self.Faces.Data)
		print 'material count: %i' % len(self.Materials.Data)
		print 'bone count: %i' % len(self.Bones.Data)
		print 'inlfuence count: %i' % len(self.Influences.Data)
		print '-------------------------'
		
# PSA FILE NOTES FROM UDN:
#
#	The raw key array holds all the keys for all the bones in all the specified sequences, 
#	organized as follows:
#	For each AnimInfoBinary's sequence there are [Number of bones] times [Number of frames keys] 
#	in the VQuatAnimKeys, laid out as tracks of [numframes] keys for each bone in the order of 
#	the bones as defined in the array of FnamedBoneBinary in the PSA. 
#
#	Once the data from the PSK (now digested into native skeletal mesh) and PSA (digested into 
#	a native animation object containing one or more sequences) are associated together at runtime, 
#	bones are linked up by name. Any bone in a skeleton (from the PSK) that finds no partner in 
#	the animation sequence (from the PSA) will assume its reference pose stance ( as defined in 
#	the offsets & rotations that are in the VBones making up the reference skeleton from the PSK)

	
class PSAFile:
	def __init__(self):
		self.GeneralHeader = VChunkHeader("ANIMHEAD", 0)
		self.Bones = FileSection("BONENAMES", SIZE_FNAMEDBONEBINARY)	#FNamedBoneBinary
		self.Animations = FileSection("ANIMINFO", SIZE_ANIMINFOBINARY)	#AnimInfoBinary
		self.RawKeys = FileSection("ANIMKEYS", SIZE_VQUATANIMKEY)	#VQuatAnimKey
		
		# this will take the format of key=Bone Name, value = (BoneIndex, Bone Object)
		# THIS IS NOT DUMPED
		self.BoneLookup = {} 
		
	def dump(self):
		data = self.Generalheader.dump() + self.Bones.dump() + self.Animations.dump() + self.RawKeys.dump()
		return data
	
	def AddBone(self, b):
		#LOUD
		#print "AddBone: " + b.Name
		self.Bones.Data.append(b)
		
	def AddAnimation(self, a):
		#LOUD
		#print "AddAnimation: %s, TotalBones: %i, AnimRate: %f, NumRawFrames: %i, TrackTime: %f" % (a.Name, a.TotalBones, a.AnimRate, a.NumRawFrames, a.TrackTime)
		self.Animations.Data.append(a)
		
	def AddRawKey(self, k):
		#LOUD
		#print "AddRawKey [%i]: Time: %f, Quat: x=%f, y=%f, z=%f, w=%f, Position: x=%f, y=%f, z=%f" % (len(self.RawKeys.Data), k.Time, k.Orientation.X, k.Orientation.Y, k.Orientation.Z, k.Orientation.W, k.Position.X, k.Position.Y, k.Position.Z)
		self.RawKeys.Data.append(k)
		
	def UpdateHeaders(self):
		self.Bones.UpdateHeader()
		self.Animations.UpdateHeader()
		self.RawKeys.UpdateHeader()
		
	def GetBoneByIndex(self, bone_index):
		if bone_index >= 0 and len(self.Bones.Data) > bone_index:
			return self.Bones.Data[bone_index]
	
	
	def IsEmpty(self):
		return (len(self.Bones.Data) == 0 or len(self.Animations.Data) == 0)
	
	def StoreBone(self, b):
		self.BoneLookup[b.Name] = [-1, b]
					
	def UseBone(self, bone_name):
		if bone_name in self.BoneLookup:
			bone_data = self.BoneLookup[bone_name]
			
			if bone_data[0] == -1:
				bone_data[0] = len(self.Bones.Data)
				self.AddBone(bone_data[1])
				#self.Bones.Data.append(bone_data[1])
			
			return bone_data[0]
			
	
	def GetBoneByName(self, bone_name):
		if bone_name in self.BoneLookup:
			bone_data = self.BoneLookup[bone_name]
			return bone_data[1]
		
	def GetBoneIndex(self, bone_name):
		if bone_name in self.BoneLookup:
			bone_data = self.BoneLookup[bone_name]
			return bone_data[0]
		
	def dump(self):
		self.UpdateHeaders()
		data = self.GeneralHeader.dump() + self.Bones.dump() + self.Animations.dump() + self.RawKeys.dump()
		return data
		
	def PrintOut(self):
		print '--- PSA FILE EXPORTED ---'
		print 'bone count: %i' % len(self.Bones.Data)
		print 'animation count: %i' % len(self.Animations.Data)
		print 'rawkey count: %i' % len(self.RawKeys.Data)
		print '-------------------------'
		
	
####################################	
# helpers to create bone structs
def make_vbone(name, parent_index, child_count, orientation_quat, position_vect):
	bone = VBone()
	#print "----VBONE----"
	bone.Name = name
	#print bone.Name, "----NAME----"
	bone.ParentIndex = parent_index
	#print bone.ParentIndex, "----PARENT----"
	bone.NumChildren = child_count
	#print bone.NumChildren, "----CHILD----"
	bone.BonePos.Orientation = orientation_quat
	bone.BonePos.Position.X = position_vect.x
	bone.BonePos.Position.Y = position_vect.y
	bone.BonePos.Position.Z = position_vect.z
	
	#these values seem to be ignored?
	#bone.BonePos.Length = tail.length
	#bone.BonePos.XSize = tail.x
	#bone.BonePos.YSize = tail.y
	#bone.BonePos.ZSize = tail.z
	return bone

def make_namedbonebinary(name, parent_index, child_count, orientation_quat, position_vect, is_real):
	bone = FNamedBoneBinary()
	#print "----namedbonebinary---"
	bone.Name = name
	#print bone.Name
	bone.ParentIndex = parent_index
	bone.NumChildren = child_count
	bone.BonePos.Orientation = orientation_quat
	bone.BonePos.Position.X = position_vect.x
	bone.BonePos.Position.Y = position_vect.y
	bone.BonePos.Position.Z = position_vect.z
	bone.IsRealBone = is_real
	return bone	
	
##################################################
#RG - check to make sure face isnt a line
def is_1d_face(blender_face):
	return ((blender_face.v[0].co == blender_face.v[1].co) or \
	(blender_face.v[1].co == blender_face.v[2].co) or \
	(blender_face.v[2].co == blender_face.v[0].co))


##################################################
# Actual object parsing functions

def parse_meshes(blender_meshes, psk_file):
	print "----- parsing meshes -----"
	#print 'blender_meshes length: %i' % (len(blender_meshes))
	
	for current_obj in blender_meshes: 
		
		current_mesh = current_obj.getData()
		#print 'current mesh name: ' + current_mesh.name
		#raw_mesh = Mesh.Get(current_mesh.name)
			
		
		# Get the world transform for the object
		object_mat = current_obj.mat 
		
		# add material 0
		#m = VMaterial()
		#m.MaterialName = "Mat0"
		#psk_file.AddMaterial(m)

		#print 'faces: %i' % (len(current_mesh.faces))
		#print 'verts: %i' % (len(current_mesh.verts))
		#print 'has face UV: %i' % (current_mesh.hasFaceUV())
	
		points = ObjMap()
		wedges = ObjMap()
			
		discarded_face_count = 0
		
		#print ' -- Dumping Mesh Faces -- '
		for current_face in current_mesh.faces:
			#print ' -- Dumping UVs -- '
			#print current_face.uv

			if len(current_face.v) != 3:
				raise RuntimeError("Non-triangular face (%i)" % len(current_face.v))
				
				
				#todo: add two fake faces made of triangles?
				
			#RG - apparently blender sometimes has problems when you do quad to triangle 
			#	conversion, and ends up creating faces that have only TWO points -
			# 	one of the points is simply in the vertex list for the face twice. 
			#	This is bad, since we can't get a real face normal for a LINE, we need 
			#	a plane for this. So, before we add the face to the list of real faces, 
			#	ensure that the face is actually a plane, and not a line. If it is not 
			#	planar, just discard it and notify the user in the console after we're
			#	done dumping the rest of the faces
			
			if not is_1d_face(current_face):
			
				wedge_list = []
				vect_list = []
				
				#get or create the current material
				m = psk_file.GetMatByIndex(current_face.mat)
				#print 'material: %i' % (current_face.mat) #EDIT OUT
				
				for i in range(3):
					vert = current_face.v[i]

					if len(current_face.uv) != 3:
						#print "WARNING: Current face is missing UV coordinates - writing 0,0..."
						uv = [0.0, 0.0]
					else:
						uv = list(current_face.uv[i])
						
					
					#flip V coordinate because UEd requires it and DOESN'T flip it on its own like it
					#does with the mesh Y coordinates.
					#this is otherwise known as MAGIC-2
					uv[1] = 1.0 - uv[1]
					
					#print "Vertex UV: ", uv, " UVCO STUFF:", vert.uvco.x, vert.uvco.y

					# RE - Append untransformed vector (for normal calc below)
					# TODO: convert to Blender.Mathutils
					vect_list.append(FVector(vert.co.x, vert.co.y, vert.co.z))

					# Transform position for export
					vpos = vert.co * object_mat

					# Create the point
					p = VPoint()
					p.Point.X = vpos.x
					p.Point.Y = vpos.y
					p.Point.Z = vpos.z

					# Create the wedge
					w = VVertex()
					w.MatIndex = current_face.mat
					w.PointIndex = points.get(p) # get index from map

					w.U = uv[0]
					w.V = uv[1]

					wedge_index = wedges.get(w)
					wedge_list.append(wedge_index)
					
					
					#print results
					#print 'result PointIndex=%i, U=%f, V=%f, wedge_index=%i' % (
					#	w.PointIndex,
					#	w.U,
					#	w.V,
					#	wedge_index)

				# Determine face vertex order
				# get normal from blender
				no = current_face.no

				# TODO: convert to Blender.Mathutils
				# convert to FVector
				norm = FVector(no[0], no[1], no[2])

				# Calculate the normal of the face in blender order
				tnorm = vect_list[1].sub(vect_list[0]).cross(vect_list[2].sub(vect_list[1]))

				# RE - dot the normal from blender order against the blender normal
				# this gives the product of the two vectors' lengths along the blender normal axis
				# all that matters is the sign
				dot = norm.dot(tnorm)

				# print results
				#print 'face norm: (%f,%f,%f), tnorm=(%f,%f,%f), dot=%f' % (
				#	norm.X, norm.Y, norm.Z,
				#	tnorm.X, tnorm.Y, tnorm.Z,
				#	dot)

				tri = VTriangle()
				# RE - magic: if the dot product above > 0, order the vertices 2, 1, 0
				#        if the dot product above < 0, order the vertices 0, 1, 2
				#        if the dot product is 0, then blender's normal is coplanar with the face
				#        and we cannot deduce which side of the face is the outside of the mesh
				if (dot > 0):
					(tri.WedgeIndex2, tri.WedgeIndex1, tri.WedgeIndex0) = wedge_list
				elif (dot < 0):
					(tri.WedgeIndex0, tri.WedgeIndex1, tri.WedgeIndex2) = wedge_list
				else:
					raise RuntimeError("normal vector coplanar with face! points:", current_face.v[0].co, current_face.v[1].co, current_face.v[2].co)
				
				tri.MatIndex = current_face.mat
				psk_file.AddFace(tri)
				
			else:
				discarded_face_count = discarded_face_count + 1
				
			
		for point in points.items():
			psk_file.AddPoint(point)
			
		for wedge in wedges.items():
			psk_file.AddWedge(wedge)
	
	
		#RG - if we happend upon any non-planar faces above that we've discarded, 
		#	just let the user know we discarded them here in case they want 
		#	to investigate
	
		if discarded_face_count > 0: 
			print "INFO: Discarded %i non-planar faces." % (discarded_face_count)
		
		
				
		
		#RG - walk through the vertex groups and find the indexes into the PSK points array 
		#for them, then store that index and the weight as a tuple in a new list of 
		#verts for the group that we can look up later by bone name, since Blender matches
		#verts to bones for influences by having the VertexGroup named the same thing as
		#the bone
		vertex_groups = current_mesh.getVertGroupNames()
		for group in vertex_groups:
			verts = current_mesh.getVertsFromGroup(group, 1)
			
			vert_list = []
			
			for vert_data in verts:
				vert_index = vert_data[0]
				vert_weight = vert_data[1]

				vert = current_mesh.verts[vert_index]

				vpos = vert.co * object_mat


				p = VPoint()
				p.Point.X = vpos.x
				p.Point.Y = vpos.y
				p.Point.Z = vpos.z
				
				point_index = points.get(p)
				
				v_item = (point_index, vert_weight)
				vert_list.append(v_item)
				
				#print 'VertexGroup: %s, vert index=%i, point_index=%i' % (group, vert_index, point_index)
			
			psk_file.VertexGroups[group] = vert_list
	
			

def make_fquat(bquat):
	quat = FQuat()
	
	#flip handedness for UT = set x,y,z to negative (rotate in other direction)
	quat.X = -bquat.x
	quat.Y = -bquat.y
	quat.Z = -bquat.z

	quat.W = bquat.w
	return quat


# TODO: remove this 1am hack
#This fixed id parent number index list the default I think it is zero for main bone that is parent of the child
#nbone = 1 #default
nbone = 0
# first pass to the main root first then start the coutner to one later.	
#parse_bone(current_bone, psk_file, psa_file, 0, 1, current_obj.mat) this is from the begin code execute look like first code enter
def parse_bone(blender_bone, psk_file, psa_file, parent_id, is_root_bone, parent_mat):
	global nbone 	# look it's evil!
	
	#print ' --- Dumping Bone --- '
	print 'blender bone name: ' + blender_bone.name
	print "nbone",nbone
	#print "BONE CHILD:",len(blender_bone.children), "LENGTH"
	#print dir(blender_bone)
	#print "PARENT NUMBER HELLO:", dir(blender_bone)#, len(blender_bone.parent)
	#print "PARENT NUMBER HELLO:", blender_bone.length
	#if blender_bone.hasChildren():
	#	child_count = len(blender_bone.children)
	#else:
	#	child_count = 0
	#print "[CHILD COUNT]:", child_count
	
	
	#Note the is the parent this how many childs does it have for the bones
	child_count = len(blender_bone.children)
	
	if (parent_mat):
		head = blender_bone.head['BONESPACE'] * parent_mat
		tail = blender_bone.tail['BONESPACE'] * parent_mat
		rot_mat = blender_bone.matrix['BONESPACE'] * parent_mat.rotationPart()
		quat = make_fquat(rot_mat.toQuat())
	else:
		head = blender_bone.head['BONESPACE']
		tail = blender_bone.tail['BONESPACE']
		quat = make_fquat(blender_bone.matrix['BONESPACE'].toQuat())
		
	bone_vect = tail-head
	#LOUD
	#print "Head: ", head
	#print "Tail: ", tail
	#print "Quat: ", quat
	
	final_parent_id = parent_id

	#RG/RE -
	#if we are not seperated by a small distance, create a dummy bone for the displacement
	#this is only needed for root bones, since UT assumes a connected skeleton, and from here
	#down the chain we just use "tail" as an endpoint
	#if(head.length > 0.001 and is_root_bone == 1):
	#print "[parent id]:", parent_id , " [child_count]:",child_count, 
	
	if(0):#Not sure this is even use 	
		pb = make_vbone("dummy_" + blender_bone.name, nbone, 1, FQuat(), head)
		psk_file.AddBone(pb)
		pbb = make_namedbonebinary("dummy_" + blender_bone.name, nbone, 1, FQuat(), head, 0)
		psa_file.StoreBone(pbb)
		
		final_parent_id = nbone
		nbone = nbone + 1
		tail = tail-head
		#print "CREATE DUMMY"
	my_id = nbone
	#print "MY ID:",my_id
	
	#Create Defualt Root Bone Still need work on it 
	if final_parent_id == 0:
		#print "Main parent", final_parent_id
		pb = make_vbone(blender_bone.name, nbone, child_count, quat, head)
		psk_file.AddBone(pb)
		pbb = make_namedbonebinary(blender_bone.name, nbone, child_count,quat,head, 0)
		psa_file.StoreBone(pbb)
	else:
		pb = make_vbone(blender_bone.name, nbone, child_count, quat, head)
		psk_file.AddBone(pb)
		pbb = make_namedbonebinary(blender_bone.name, nbone, child_count, quat, head, 1)
		psa_file.StoreBone(pbb)
		
	nbone = nbone + 1
	print "nbone:",nbone,"parent_id",parent_id,"Final Parent Id: ",final_parent_id,"Child Count:",child_count
	
	#RG - dump influences for this bone - use the data we collected in the mesh dump phase
	# to map our bones to vertex groups
	if blender_bone.name in psk_file.VertexGroups:
		vertex_list = psk_file.VertexGroups[blender_bone.name]
		if len(vertex_list):#Check if there any array incase it add on by chance 
			#print "There is weight in the array"
			for vertex_data in vertex_list:
				#print "WEIGHT AND VERTEX"
				#print vertex_data
				point_index = vertex_data[0]
				vertex_weight = vertex_data[1]
				influence = VRawBoneInfluence()
				influence.Weight = vertex_weight
				influence.PointIndex = point_index
				influence.BoneIndex = my_id
				print my_id
				psk_file.AddInfluence(influence)
				if nbone != 0:
					print "ADD MAIN ROOT"
					influence0 = VRawBoneInfluence()
					influence0.Weight = vertex_weight
					influence0.PointIndex = point_index
					influence0.BoneIndex = 0
					psk_file.AddInfluence(influence0)
				#influence.BoneIndex = nbone
				#print "BONE INDEX:", nbone , "POINT OF INDEX:", point_index, "WEIGHT SCALE:",vertex_weight
				#print influence.PointIndex
				#print "Weight", vertex_weight, ":",my_id,point_index,"PARENT ID:",parent_id
				#print 'Adding Bone Influence for [%s] = Point Index=%i, Weight=%f' % (blender_bone.name, point_index, vertex_weight)
				
				#print len(vertex_list)
	#nbone = nbone + 1
	my_id = nbone
	#recursively dump child bones
	if blender_bone.hasChildren():
		for current_child_bone in blender_bone.children:
			parse_bone(current_child_bone, psk_file, psa_file, my_id, 0, None)


def make_armature_bone(blender_object, psk_file, psa_file):
	# this makes a dummy bone to offset the armature origin for each armature

	global nbone #hacky
	
	my_id = nbone
	armature = blender_object.getData()
	
	#screw efficiency! just calc this again
	bones = [x for x in armature.bones.values() if not x.hasParent()]
	child_count = len(bones)
	object_matrix = blender_object.mat
	
	quat = make_fquat(object_matrix.toQuat())
	tail = object_matrix.translationPart()

	#for psk file	
	root_bone = make_vbone(blender_object.name, 0, child_count, quat, tail)
	print root_bone , "ROOT BONE"
	psk_file.AddBone(root_bone)
	
	
	#for psa file
	root_bone_binary = make_namedbonebinary(blender_object.name, 0, child_count, quat, tail, 0)
	psa_file.StoreBone(root_bone_binary)
	
	nbone = nbone + 1
	return my_id
	
"""
This scetion deal with the armature know as bones.
No more than one main armature or bone to be the main parent else it might crash your unreal engine.
"""	
def parse_armature(blender_armature, psk_file, psa_file):
	print "----- parsing armature -----"
	#print 'blender_armature length: %i' % (len(blender_armature))
	#magic 0 sized root bone for UT - this is where all armature dummy bones will attach
	#dont increment nbone here because we initialize it to 1 (hackity hackity hack)
	#count top level bones first. screw efficiency again - ohnoz it will take dayz to runz0r!
	
	child_count = 0
	for current_obj in blender_armature: 
		current_armature = current_obj.getData()
		bones = [x for x in current_armature.bones.values() if not x.hasParent()]
		child_count += len(bones)
		print "CHILD COUNT:", child_count, "COUNTER"

	for current_obj in blender_armature: #looking for how many armatures it should be one build 
		print 'current armature name: ' + current_obj.name
		#print current_obj, "Hello-BONES"
		current_armature = current_obj.getData()
		#armature_id = make_armature_bone(current_obj, psk_file, psa_file)
		#print current_armature.hasParent()
		#we dont want children here - only the top level bones of the armature itself
		#we will recursively dump the child bones as we dump these bones
		bones = [x for x in current_armature.bones.values() if not x.hasParent()]
		#print dir(bones), "---PARENT--"
		print bones, "<-MAIN BONE"
		print "---BONE LIST---"
		for current_bone in bones:
			#print len(bones)
			#print current_bone.name , "<-BONE NAME"
			print "FUNCTION FOR PASRSE_BONE"
			#first the code is  pass into the main root.
			parse_bone(current_bone, psk_file, psa_file, 0, 1, current_obj.mat)
		print "END BONE LIST"	

# get blender objects by type		
def get_blender_objects(objects, type):
	return [x for x in objects if x.getType() == type]
			
#strips current extension (if any) from filename and replaces it with extension passed in
def make_filename_ext(filename, extension):

	new_filename = ''
	extension_index = filename.rfind('.')
	
	if extension_index == -1:
		new_filename = filename + extension
	else:
		new_filename = filename[0:extension_index] + extension
		
	return new_filename

# returns the quaternion Grassman product a*b
# this is the same as the rotation a(b(x)) 
# (ie. the same as B*A if A and B are matrices representing 
# the rotations described by quaternions a and b)
def grassman(a, b):	
	return Blender.Mathutils.Quaternion(
		a.w*b.w - a.x*b.x - a.y*b.y - a.z*b.z,
		a.w*b.x + a.x*b.w + a.y*b.z - a.z*b.y,
		a.w*b.y - a.x*b.z + a.y*b.w + a.z*b.x,
		a.w*b.z + a.x*b.y - a.y*b.x + a.z*b.w)
	
	

def parse_animation(blender_scene, psa_file):
	print "----- parsing animation -----"
	blender_context = blender_scene.getRenderingContext()
	
	anim_rate = blender_context.framesPerSec()
	#print 'Scene: %s Start Frame: %i, End Frame: %i' % (blender_scene.getName(), blender_context.startFrame(), blender_context.endFrame())
	#print "Frames Per Sec: %i" % anim_rate
	
	export_objects = blender_scene.objects
	blender_armatures = get_blender_objects(export_objects, 'Armature')
	
	cur_frame_index = 0
	
	for act in Armature.NLA.GetActions().values():
		
		action_name = act.getName()
		action_keyframes = act.getFrameNumbers()
		start_frame = min(action_keyframes)
		end_frame = max(action_keyframes)
		scene_frames = xrange(start_frame, end_frame+1) 
		#scene_frames = action_keyframes
		
		frame_count = len(scene_frames)
				
		anim = AnimInfoBinary()
		anim.Name = action_name
		anim.Group = "" #wtf is group?
		anim.NumRawFrames = frame_count
		anim.AnimRate = anim_rate
		anim.FirstRawFrame = cur_frame_index
		count_previous_keys = len(psa_file.RawKeys.Data)
		 		
		#print "------------ Action: %s, frame keys:" % (action_name) , action_keys
		print "----- Action: %s" % action_name;
		
		unique_bone_indexes = {}
		
		for obj in blender_armatures:
			
			current_armature = obj.getData()
			act.setActive(obj)
			
			# bone lookup table
			bones_lookup =  {}
			for bone in current_armature.bones.values():
				bones_lookup[bone.name] = bone
			
			
			frame_count = len(scene_frames)
			#print "Frame Count: %i" % frame_count
			pose_data = obj.getPose()
			
			#these must be ordered in the order the bones will show up in the PSA file!
			ordered_bones = {}
			ordered_bones = sorted([(psa_file.UseBone(x.name), x) for x in pose_data.bones.values()], key=operator.itemgetter(0))
			
			
			#############################
			# ORDERED FRAME, BONE
			#for frame in scene_frames:
			
			for i in range(frame_count):
				frame = scene_frames[i]
				
				#LOUD
				#print "==== outputting frame %i ===" % frame
				
				if frame_count > i+1:
					next_frame = scene_frames[i+1]
					#print "This Frame: %i, Next Frame: %i" % (frame, next_frame)
				else:
					next_frame = -1
					#print "This Frame: %i, Next Frame: NONE" % frame
					
						
				Blender.Set('curframe', frame)
				
				cur_frame_index = cur_frame_index + 1
				for bone_data in ordered_bones:
					bone_index = bone_data[0]
					pose_bone = bone_data[1]
					blender_bone = bones_lookup[pose_bone.name]
					
				
					#just need the total unique bones used, later for this AnimInfoBinary
					unique_bone_indexes[bone_index] = bone_index
					#LOUD
					#print "-------------------", pose_bone.name
					
					head = blender_bone.head['BONESPACE']
					tail = blender_bone.tail['BONESPACE']
					quat = blender_bone.matrix['BONESPACE'].toQuat()
					
					#print "Head: ", head
					#print "Tail: ", tail
					#print "Quat: ", quat
					
					#print "orig quat: ", quat
					#print "pose quat: ", pose_bone.quat
					
					#head = pose_bone.head
					quat = grassman(quat, pose_bone.quat)
					
					#WOW
					tail = (pose_bone.quat * (tail-head)) + head + pose_bone.loc
					
					# no parent?  apply armature transform
					if not blender_bone.hasParent():
						parent_mat = obj.mat
						head = head * parent_mat
						tail = tail * parent_mat
						quat = grassman(parent_mat.toQuat(), quat)
					
					print "Head: ", head
					print "Tail: ", tail
					print "Quat: ", quat
					#print "L0c: ", pose_bone.loc
					
					vkey = VQuatAnimKey()
					vkey.Position.X = tail.x
					vkey.Position.Y = tail.y
					vkey.Position.Z = tail.z
					
					#vkey.Position.X = 0.0
					#vkey.Position.Y = 1.0
					#vkey.Position.Z = 0.0
					
					
					vkey.Orientation = make_fquat(quat)
					
					#time frm now till next frame = diff / framesPerSec
					
					if next_frame >= 0:
						diff = next_frame - frame
					else:
						diff = 1.0
					
					#print "Diff = ", diff
					vkey.Time = float(diff)/float(blender_context.framesPerSec())
					
					psa_file.AddRawKey(vkey)
					
			#done looping frames
			
		#done looping armatures
		#continue adding animInfoBinary counts here
		
		anim.TotalBones = len(unique_bone_indexes)
		anim.TrackTime = float(frame_count) / anim.AnimRate
		psa_file.AddAnimation(anim)

def psa_animation(blender_scene, psa_file):
	global endframe,startframe,string
	print "FRAME NAME:",string
	print "FRAME START:",startframe
	print "FRAME END:",endframe
	print "----- parsing animation -----"
	#blender_context = blender_scene.getRenderingContext()
	
	anim_rate = endframe
	print anim_rate, "ANIMTIONA RATE"
	#print 'Scene: %s Start Frame: %i, End Frame: %i' % (blender_scene.getName(), blender_context.startFrame(), blender_context.endFrame())
	#print "Frames Per Sec: %i" % anim_rate
	
	#export_objects = blender_scene.objects
	blender_armatures = Blender.Object.Get('Armature')
	print blender_armatures
	print "ANIMATION01"
	
	cur_frame_index = 0
	
	#for act in Armature.NLA.GetActions().values():
	action_name = string
	action_keyframes = Blender.Get("curframe")
	start_frame = startframe
	end_frame = endframe
	#scene_frames = xrange(start_frame, end_frame+1) 
	#scene_frames = action_keyframes
'''		
	frame_count = len(scene_frames)
		
	anim = AnimInfoBinary()
	anim.Name = action_name
	#print "ACTION NAME:",action_name
	anim.Group = "" #wtf is group?
	anim.NumRawFrames = frame_count
	anim.AnimRate = anim_rate
	anim.FirstRawFrame = cur_frame_index
	count_previous_keys = len(psa_file.RawKeys.Data)
	print "ANIMATION02"	
	#print "------------ Action: %s, frame keys:" % (action_name) , action_keys
	print "----- Action: %s" % action_name;
		
	unique_bone_indexes = {}
	print "blender_armatures",blender_armatures
	for obj in blender_armatures:
			
		current_armature = obj.getData()
		act.setActive(obj)
			
		# bone lookup table
		bones_lookup =  {}
		for bone in current_armature.bones.values():
			bones_lookup[bone.name] = bone
			
			
		frame_count = len(scene_frames)
		#print "Frame Count: %i" % frame_count
		pose_data = obj.getPose()
			
		#these must be ordered in the order the bones will show up in the PSA file!
		ordered_bones = {}
		ordered_bones = sorted([(psa_file.UseBone(x.name), x) for x in pose_data.bones.values()], key=operator.itemgetter(0))
			
			
		#############################
		# ORDERED FRAME, BONE
		#for frame in scene_frames:
		for i in range(frame_count):
			frame = scene_frames[i]
			#LOUD
			#print "==== outputting frame %i ===" % frame
			if frame_count > i+1:
				next_frame = scene_frames[i+1]
				#print "This Frame: %i, Next Frame: %i" % (frame, next_frame)
			else:
				next_frame = -1
				#print "This Frame: %i, Next Frame: NONE" % frame
			Blender.Set('curframe', frame)
			
			cur_frame_index = cur_frame_index + 1
			for bone_data in ordered_bones:
				bone_index = bone_data[0]
				pose_bone = bone_data[1]
				blender_bone = bones_lookup[pose_bone.name]
					
				
				#just need the total unique bones used, later for this AnimInfoBinary
				unique_bone_indexes[bone_index] = bone_index
				#LOUD
				#print "-------------------", pose_bone.name
					
				head = blender_bone.head['BONESPACE']
				tail = blender_bone.tail['BONESPACE']
				quat = blender_bone.matrix['BONESPACE'].toQuat()
					
				#print "Head: ", head
				#print "Tail: ", tail
				#print "Quat: ", quat
				#print "orig quat: ", quat
				#print "pose quat: ", pose_bone.quat
					
				#head = pose_bone.head
				quat = grassman(quat, pose_bone.quat)
					
				#WOW
				tail = (pose_bone.quat * (tail-head)) + head + pose_bone.loc
					
				# no parent?  apply armature transform
				if not blender_bone.hasParent():
					parent_mat = obj.mat
					head = head * parent_mat
					tail = tail * parent_mat
					quat = grassman(parent_mat.toQuat(), quat)
					
				print "Head: ", head
				print "Tail: ", tail
				print "Quat: ", quat
				#print "L0c: ", pose_bone.loc
					
				vkey = VQuatAnimKey()
				vkey.Position.X = tail.x
				vkey.Position.Y = tail.y
				vkey.Position.Z = tail.z
					
				#vkey.Position.X = 0.0
				#vkey.Position.Y = 1.0
				#vkey.Position.Z = 0.0
				
				vkey.Orientation = make_fquat(quat)
				
				#time frm now till next frame = diff / framesPerSec
				
				if next_frame >= 0:
					diff = next_frame - frame
				else:
					diff = 1.0
				
				#print "Diff = ", diff
				vkey.Time = float(diff)/float(cur_frame_index)
				
				psa_file.AddRawKey(vkey)
				
		#done looping frames
		
	#done looping armatures
	#continue adding animInfoBinary counts here
		
	anim.TotalBones = len(unique_bone_indexes)
	anim.TrackTime = float(frame_count) / anim.AnimRate
	psa_file.AddAnimation(anim)
'''
	

def fs_callback(filename):
	print "======EXPORTING TO UNREAL SKELETAL MESH FORMATS========\r\n"
	
	psk = PSKFile()
	psa = PSAFile()
	
	#sanity check - this should already have the extension, but just in case, we'll give it one if it doesn't
	psk_filename = make_filename_ext(filename, '.psk')
	
	#make the psa filename
	psa_filename = make_filename_ext(filename, '.psa')
	
	#print 'PSK File: ' +  psk_filename
	#print 'PSA File: ' +  psa_filename
	
	blender_meshes = []
	blender_armature = []
	
	current_scene = Blender.Scene.GetCurrent()
	current_scene.makeCurrent()
	
	cur_frame = Blender.Get('curframe') #store current frame before we start walking them during animation parse
	
	objects = current_scene.getChildren()
	
	blender_meshes = get_blender_objects(objects, 'Mesh')
	blender_armature = get_blender_objects(objects, 'Armature')
	
	
	try:
	
		#######################
		# STEP 1: MESH DUMP
		# we build the vertexes, wedges, and faces in here, as well as a vertexgroup lookup table
		# for the armature parse
		parse_meshes(blender_meshes, psk)
		
	except:
		Blender.Set('curframe', cur_frame) #set frame back to original frame
		print "Exception during Mesh Parse"
		raise
	
	
	
	try:
	
		#######################
		# STEP 2: ARMATURE DUMP
		# IMPORTANT: do this AFTER parsing meshes - we need to use the vertex group data from 
		# the mesh parse in here to generate bone influences
		parse_armature(blender_armature, psk, psa) 
	
	except:
		Blender.Set('curframe', cur_frame) #set frame back to original frame
		print "Exception during Armature Parse"
		raise

	
	try:
		#######################
		# STEP 3: ANIMATION DUMP
		# IMPORTANT: do AFTER parsing bones - we need to do bone lookups in here during animation frames
		parse_animation(current_scene, psa) 
	except:
		Blender.Set('curframe', cur_frame) #set frame back to original frame
		print "Exception during Animation Parse"
		raise

	
	# reset current frame
	
	Blender.Set('curframe', cur_frame) #set frame back to original frame
	
  	
  	##########################
  	# FILE WRITE
	#RG - dump psk file
	psk.PrintOut()
	file = open(psk_filename, "wb") 
	file.write(psk.dump())
	file.close() 
	print 'Successfully Exported File: ' + psk_filename

		
	#RG - dump psa file
	if not psa.IsEmpty():
		psa.PrintOut()
		file = open(psa_filename, "wb") 
		file.write(psa.dump())
		file.close() 
		print 'Successfully Exported File: ' + psa_filename
	else:
		print 'No Animations to Export'

def PSA_EXPORT(filename):
	print "======EXPORTING TO UNREAL SKELETAL MESH FORMATS========\r\n"
	
	psk = PSKFile()
	psa = PSAFile()
	
	#make the psa filename
	psa_filename = make_filename_ext(filename, '.psa')
	
	#print 'PSK File: ' +  psk_filename
	#print 'PSA File: ' +  psa_filename
	
	blender_meshes = []
	blender_armature = []
	
	current_scene = Blender.Scene.GetCurrent()
	current_scene.makeCurrent()
	
	cur_frame = Blender.Get('curframe') #store current frame before we start walking them during animation parse
	
	objects = current_scene.getChildren()
	
	blender_meshes = get_blender_objects(objects, 'Mesh')
	blender_armature = get_blender_objects(objects, 'Armature')
	
	
	try:
	
		#######################
		# STEP 1: MESH DUMP
		# we build the vertexes, wedges, and faces in here, as well as a vertexgroup lookup table
		# for the armature parse
		parse_meshes(blender_meshes, psk)
		
	except:
		Blender.Set('curframe', cur_frame) #set frame back to original frame
		print "Exception during Mesh Parse"
		raise
	
	
	
	try:
	
		#######################
		# STEP 2: ARMATURE DUMP
		# IMPORTANT: do this AFTER parsing meshes - we need to use the vertex group data from 
		# the mesh parse in here to generate bone influences
		parse_armature(blender_armature, psk, psa) 
	
	except:
		Blender.Set('curframe', cur_frame) #set frame back to original frame
		print "Exception during Armature Parse"
		raise

	
	try:
		#######################
		# STEP 3: ANIMATION DUMP
		# IMPORTANT: do AFTER parsing bones - we need to do bone lookups in here during animation frames
		psa_animation(current_scene, psa) 
	except:
		Blender.Set('curframe', cur_frame) #set frame back to original frame
		print "Exception during Animation Parse"
		raise

	
	# reset current frame
	Blender.Set('curframe', cur_frame) #set frame back to original frame

	#RG - dump psa file
	if not psa.IsEmpty():
		psa.PrintOut()
		file = open(psa_filename, "wb") 
		file.write(psa.dump())
		file.close() 
		print 'Successfully Exported File PSA: ' + psa_filename
	else:
		print 'No Animations to Export'
	Blender.Redraw()	
	Exit()
		
def PSK_EXPORT(filename):
	print "======EXPORTING TO UNREAL SKELETAL MESH FORMATS========\r\n"
	t = sys.time() 
	psk = PSKFile()
	psa = PSAFile()
	
	#sanity check - this should already have the extension, but just in case, we'll give it one if it doesn't
	psk_filename = make_filename_ext(filename, '.psk')
	
	blender_meshes = []
	blender_armature = []
	
	current_scene = Blender.Scene.GetCurrent()
	current_scene.makeCurrent()
	
	cur_frame = Blender.Get('curframe') #store current frame before we start walking them during animation parse
	
	objects = current_scene.getChildren()
	
	blender_meshes = get_blender_objects(objects, 'Mesh')
	blender_armature = get_blender_objects(objects, 'Armature')
	
	
	try:
		#######################
		# STEP 1: MESH DUMP
		# we build the vertexes, wedges, and faces in here, as well as a vertexgroup lookup table
		# for the armature parse
		parse_meshes(blender_meshes, psk)
		
	except:
		Blender.Set('curframe', cur_frame) #set frame back to original frame
		print "Exception during Mesh Parse"
		raise
	
	try:
		#######################
		# STEP 2: ARMATURE DUMP
		# IMPORTANT: do this AFTER parsing meshes - we need to use the vertex group data from 
		# the mesh parse in here to generate bone influences
		parse_armature(blender_armature, psk, psa) 
	except:
		Blender.Set('curframe', cur_frame) #set frame back to original frame
		print "Exception during Armature Parse"
		raise

	# reset current frame
	Blender.Set('curframe', cur_frame) #set frame back to original frame
	
  	
  	##########################
  	# FILE WRITE
	#RG - dump psk file
	psk.PrintOut()
	file = open(psk_filename, "wb") 
	file.write(psk.dump())
	file.close() 
	print 'Successfully Exported File: ' + psk_filename
	print 'My Script finished in %.2f seconds' % (sys.time()-t) 
	Blender.Redraw()
	Exit()

#if __name__ == '__main__': 
	#Window.FileSelector(fs_callback, 'Export PSK/PSA File', sys.makename(ext='.psk'))
	#fs_callback('c:\\ChainBenderSideTurret.psk')
	
from Blender import NMesh
from Blender.BGL import *
from Blender.Draw import *
from Blender import Draw, BGL
import math
from math import *
from Blender import Scene, Mesh, Window, sys 

def draw():
		global EVENT_NOEVENT,EVENT_DRAW,EVENT_EXIT,EVENT_PSK_EXT,EVENT_PSA_EXT,EVENT_STARTFRAME,EVENT_ENDFRAME,startframe,endframe,maxframe,EVENT_FRAMENAME,string
		######### Draw and Exit Buttons
		#Button("File Path",EVENT_FILEPATH , 10, Menu_Height*6, 80, 18)
		#Button("Check Mesh",EVENT_CHECKMESH, 10, Menu_Height*5, 80, 18)
		#Button("Export",EVENT_EXPORT, 10, Menu_Height*4, 80, 18)
		
		string = Draw.String("Frame Name: ", EVENT_FRAMENAME, 10, Menu_Height*6, 160, 18, string.val, 20, "Name of the Frame current use.")
		
		startframe = Draw.Number("Start Frame", EVENT_STARTFRAME, 10, Menu_Height*5, 160, 18, startframe.val, 1, maxframe, "A Start Frame Animation")
		BGL.glRasterPos2i(200,Menu_Height*5)
		Draw.Text("The start frame button has value %d." % startframe.val)
		endframe = Draw.Number("End Frame", EVENT_ENDFRAME, 10, Menu_Height*4, 160, 18, endframe.val, 1, maxframe, "A End Frame Animation")
		BGL.glRasterPos2i(200,Menu_Height*4)
		Draw.Text("The end frame button has value %d." % endframe.val)
		BGL.glRasterPos2i(10,Menu_Height*3)
		Draw.Text("Current Setting For Max Frame: %d." % maxframe)
		
		Button("EXPORT PSK",EVENT_PSK_EXT, 10, Menu_Height*2, 100, 18)
		Button("EXPORT PSA",EVENT_PSA_EXT, 10, Menu_Height*7, 100, 18)
		Button("Exit",EVENT_EXIT , 140, 10, 80, 18)
		
		print "Draw GUI"
	
def event(evt, val):
	#if (evt == QKEY and not val):
	if (evt == QKEY):
		print "Hello EXIT"
		Exit()

def bevent(evt):
		global EVENT_NOEVENT,EVENT_DRAW,EVENT_EXIT,EVENT_PSK_EXT,EVENT_PSA_EXT,T_Radius,T_NumberOfSides,EVENT_STARTFRAME,EVENT_ENDFRAME,startframe,endframe,maxframe,EVENT_FRAMENAME,string
		######### Manages GUI events
		if (evt == EVENT_EXIT):
			Exit()
		elif (evt == EVENT_PSK_EXT):
			print "Hello"
			if __name__ == '__main__': 
				Window.FileSelector(PSK_EXPORT, 'Export PSK File', sys.makename(ext='.psk'))
		elif evt == EVENT_PSA_EXT:
			if __name__ == '__main__': 
				Window.FileSelector(PSA_EXPORT, 'Export PSA File', sys.makename(ext='.psa'))
		elif evt == EVENT_STARTFRAME:
			Blender.Redraw()
		elif evt == EVENT_ENDFRAME:
			Blender.Redraw()
			#PSK_EXPORT("test")
		#elif (evt == EVENT_DRAW):
		#	print "Draw Object"
		#	Blender.Redraw()

Register(draw, event, bevent)	
